package com.yangfan.screenshot.utils;

import android.graphics.Bitmap;
import android.graphics.Color;

import com.yangfan.screenshot.log.LogUtil;

/**
 * @author : yangfan_rj
 * @date : 2022/12/8-20:53
 * desc   : 拼接算法，尽量不要动
 */
public class StitchUtil {
    private static String TAG = StitchUtil.class.getSimpleName();

    /**
     * 不参与比较的左侧宽度
     */
    private static final int LEFT_WIDTH = (int) (ScreenUtil.instance.getWidth() * 0.23);


    public interface MergeListener {
        /**
         * 合并错误
         * @param throwable
         */
        void onError(Throwable throwable,Bitmap bitmap);
    }

    /**
     * 两个bitmap比对差异，去掉相同部分，然后后合并成一个新的bitmap
     *
     * @param bitmap  位图
     * @param bitmap2 位图2
     * @return {@link Bitmap}
     */
    public static Bitmap merge(Bitmap bitmap, Bitmap bitmap2,MergeListener mergeListener) {
        try {
            LogUtil.d(TAG,"bitmap height = " + bitmap.getHeight() + ";bitmap2 heights = " + bitmap2.getHeight());
            int diffHeight = calculationBitmapHeight(bitmap, bitmap2);
            LogUtil.d(TAG,"diffHeight = " + diffHeight);
            int[] heights = calculationHeightPosition(diffHeight, bitmap, bitmap2);
            LogUtil.d(TAG,"heights[0] = " + heights[0] + ";heights[1] = " + heights[1]);
            Bitmap createBitmap = createBitmap(bitmap, 0, 0, bitmap.getWidth(), heights[0]);
            if (heights[1] != 0) {
                bitmap2 = createBitmap(bitmap2, 0, heights[1], bitmap2.getWidth(), bitmap2.getHeight() - heights[1]);
            }
            Bitmap mergeBitmap = BitmapUtil.mergeBitmap(createBitmap, bitmap2);
            createBitmap.recycle();
            return mergeBitmap;
        } catch (Throwable throwable) {
            throwable.printStackTrace();
            if (mergeListener != null) {
                mergeListener.onError(throwable,bitmap);
            }
            return bitmap;
        }
    }

    /**
     * 比较两张bitmap是否完全相等，以判断滑动是否到底部
     *
     * 只比较图片的一半高度，提高效率
     *
     * @param bitmap
     * @param bitmap2
     * @return
     */
    public static boolean bitmapEqual(Bitmap bitmap,Bitmap bitmap2) {
        if (bitmap.getHeight() != bitmap2.getHeight()
                && bitmap.getWidth() != bitmap2.getWidth()) {
            LogUtil.d(TAG,"比较图片的高宽不同，直接返回false");
            return false;
        }

        for (int height = bitmap.getHeight() / 2; height < bitmap.getHeight(); height++) {
            int[] pixels = new int[bitmap.getWidth()];
            int[] pixels2 = new int[bitmap2.getWidth()];
            // 从底部开始一行一行的取颜色数组
            bitmap.getPixels(pixels, 0, bitmap.getWidth(), 0, height, bitmap.getWidth(), 1);
            bitmap2.getPixels(pixels2, 0, bitmap2.getWidth(), 0, height, bitmap2.getWidth(), 1);

            if (!pixelsEqual(pixels,pixels2)) {
                return false;
            }
        }

        return true;
    }

    /**
     * 找出相同部分的高度
     *
     * @param bitmap  位图
     * @param bitmap2 bitmap2
     * @return int
     */
    private static int calculationBitmapHeight(Bitmap bitmap, Bitmap bitmap2) {
        int navigationBarHeight = ScreenUtil.instance.getNavigationBarHeight();
        int statusBarHeight = ScreenUtil.instance.getStatusBarHeight();
        int height = bitmap.getHeight() - navigationBarHeight;
        for (int height2 = bitmap2.getHeight() - navigationBarHeight; height > statusBarHeight && height2 > statusBarHeight; height2--) {
            int[] pixels = new int[bitmap.getWidth()];
            // 从底部开始一行一行的取颜色数组
            bitmap.getPixels(pixels, 0, bitmap.getWidth() - LEFT_WIDTH, LEFT_WIDTH, height, bitmap.getWidth() - LEFT_WIDTH, 1);
            if (!calculationColorDiff(pixels, 0.9f)) {
                int[] pixels2 = new int[bitmap2.getWidth()];
                bitmap2.getPixels(pixels2, 0, bitmap2.getWidth() - LEFT_WIDTH, LEFT_WIDTH, height2, bitmap2.getWidth() - LEFT_WIDTH, 1);
                if (!pixelsDiffPercent(pixels, pixels2, 0.4f)) {
                    return height;
                }
            }
            height--;
        }

        return bitmap.getHeight();
    }

    /**
     * 计算高度位置
     * 返回数组，第一位是第一张图的去掉相同部分的高度位置值
     * 第二位是第二张图去掉相同部分的高度位置值
     * 通过这两个值，就可以去掉相同部分的图片，然后做拼接处理
     * @param height  高度
     * @param bitmap  位图
     * @param bitmap2 bitmap2
     * @return {@link int[]}
     */
    private static int[] calculationHeightPosition(int height, Bitmap bitmap, Bitmap bitmap2) {
        int[] heights = new int[2];
        int statusBarHeight = ScreenUtil.instance.getStatusBarHeight();
        for (int i = height - 1; i > statusBarHeight; i -= 30) {
            int[] pixels = new int[bitmap.getWidth()];
            bitmap.getPixels(pixels, 0, bitmap.getWidth() - LEFT_WIDTH, LEFT_WIDTH, i, bitmap.getWidth() - LEFT_WIDTH, 1);
            if (!calculationColorDiff(pixels, 0.9f)) {
                for (int j = statusBarHeight; j < Math.min(height, bitmap2.getHeight() - statusBarHeight); j++) {
                    int[] pixels2 = new int[bitmap2.getWidth()];
                    bitmap2.getPixels(pixels2, 0, bitmap2.getWidth() - LEFT_WIDTH, LEFT_WIDTH, j, bitmap2.getWidth() - LEFT_WIDTH, 1);
                    /**
                     * 就认为找到了拼接点，返回两张图片的高度
                     */
                    if (pixelsEqual(pixels, pixels2)) {
                        heights[0] = i;
                        heights[1] = j;
                        return heights;
                    }
                }
            }
        }

        return heights;
    }

    /**
     * 计算颜色差异
     * 计算一行内的颜色差异，如果为true，代表改行颜色一样，即纯色，不需要参与比对
     *
     * @param pixels 像素
     * @param f      相似度
     * @return boolean
     */
    private static boolean calculationColorDiff(int[] pixels, float f) {
        int i = pixels[0];
        int i2 = pixels[pixels.length - 1];
        int i3 = pixels[pixels.length / 2];
        int i4 = 0;
        for (int i5 : pixels) {
            if (i5 == i || i5 == i2 || i5 == i3) {
                i4++;
            }
        }
        return (i4 * 1.0f) / pixels.length > f;
    }

    private static Bitmap createBitmap(Bitmap bitmap, int x, int y, int width, int height) {
        if (bitmap == null) {
            return null;
        }
        if (width <= 0) {
            width = bitmap.getWidth();
        }
        if (height <= 0) {
            height = bitmap.getHeight();
        }
        return Bitmap.createBitmap(bitmap, x, y, width, height);
    }

    /**
     * 对比两个像素数组，返回是否相同
     *
     * @param pixels  像素
     * @param pixels2 pixels2
     * @param f       差异度
     * @return boolean 当前的差异度小于f时，返回true
     */
    private static boolean pixelsDiffPercent(int[] pixels, int[] pixels2, float f) {
        int i = 0;
        for (int i2 = 0; i2 < Math.min(pixels.length, pixels2.length); i2++) {
            int red = Color.red(pixels[i2]);
            int green = Color.green(pixels[i2]);
            int blue = Color.blue(pixels[i2]);
            int alpha = Color.alpha(pixels[i2]);
            int red2 = Color.red(pixels2[i2]);
            int green2 = Color.green(pixels2[i2]);
            int blue2 = Color.blue(pixels2[i2]);
            int alpha2 = Color.alpha(pixels2[i2]);
            if (red == red2 && green == green2 && blue == blue2 && alpha == alpha2) {
                i++;
            }
        }

        float v = 1.0f - ((i * 1.0f) / Math.min(pixels.length, pixels2.length));
        return v < f;
    }

    private static boolean pixelsEqual(int[] pixels, int[] pixels2) {
        int i = 0;
        int length = Math.min(pixels.length, pixels2.length);
        for (int i2 = 0; i2 < length; i2++) {
            int red = Color.red(pixels[i2]);
            int green = Color.green(pixels[i2]);
            int blue = Color.blue(pixels[i2]);
            int alpha = Color.alpha(pixels[i2]);
            int red2 = Color.red(pixels2[i2]);
            int green2 = Color.green(pixels2[i2]);
            int blue2 = Color.blue(pixels2[i2]);
            int alpha2 = Color.alpha(pixels2[i2]);
            if (red == red2 && green == green2 && blue == blue2 && alpha == alpha2) {
                i++;
            }
        }
        return i == length;
    }

}
